package cn.edu.nju.ws.sview.servlets;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.cache.URILabelCache;
import cn.edu.nju.ws.sview.cache.URITypeCache;
import cn.edu.nju.ws.sview.crawler.Crawler;
import cn.edu.nju.ws.sview.crawler.Element;
import cn.edu.nju.ws.sview.database.DBOperations;
import cn.edu.nju.ws.sview.rdf.BlankNode;
import cn.edu.nju.ws.sview.rdf.PlainLiteral;
import cn.edu.nju.ws.sview.rdf.Resource;
import cn.edu.nju.ws.sview.rdf.ResourceFactory;
import cn.edu.nju.ws.sview.rdf.TypedLiteral;
import cn.edu.nju.ws.sview.rdf.URIResource;
import cn.edu.nju.ws.sview.reasoning.Atom;
import cn.edu.nju.ws.sview.reasoning.Constant;
import cn.edu.nju.ws.sview.reasoning.GroundAtom;
import cn.edu.nju.ws.sview.reasoning.KnowledgeBase;
import cn.edu.nju.ws.sview.reasoning.Predicate;
import cn.edu.nju.ws.sview.reasoning.Term;
import cn.edu.nju.ws.sview.reasoning.Variable;
import cn.edu.nju.ws.sview.reasoning.reasoner.CollectionReasoner;
import cn.edu.nju.ws.sview.reasoning.reasoner.CollectionReasoner.mEntity;
import cn.edu.nju.ws.sview.reasoning.reasoner.ViewReasoner;
import cn.edu.nju.ws.sview.reasoning.schema.ReducedClassTree;
import cn.edu.nju.ws.sview.util.PropertyList;
import cn.edu.nju.ws.sview.util.URIUtil;
import cn.edu.nju.ws.sview.views.CustomCollection;
import cn.edu.nju.ws.sview.views.CustomDataMember;
import cn.edu.nju.ws.sview.views.DataMember;
import cn.edu.nju.ws.sview.views.Entity;
import cn.edu.nju.ws.sview.views.URIDataMember;
import cn.edu.nju.ws.sview.views.data.ViewEditing.DataMemberItem;

/**
 * Servlet implementation class CollectionServlet
 */
@WebServlet("/CollectionServlet")
public class CollectionServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CollectionServlet() {
        super();
        // TODO Auto-generated constructor stub
    }
    
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		String option = null;
		String json = null;
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		if (request.getParameter("tmpcollection") != null) {
			json = request.getParameter("tmpcollection");
			option = "tmpcollection";
		}else if (request.getParameter("initViewDMList") != null) {
			json = request.getParameter("initViewDMList");
			option = "initViewDMList";
		}else if (request.getParameter("initViewDMTable") != null) {
			json = request.getParameter("initViewDMTable");
			option = "initViewDMTable";
		}
		else if (request.getParameter("foriginSet") != null) {
			json = request.getParameter("foriginSet");
			option = "foriginSet";
		}
		else if (request.getParameter("foriginSetByEqualValue") != null) {
			json = request.getParameter("foriginSetByEqualValue");
			option = "foriginSetByEqualValue";
		}
		else if (request.getParameter("foriginSetByMemberClass") != null) {
			json = request.getParameter("foriginSetByMemberClass");
			option = "foriginSetByMemberClass";
		}
		else if (request.getParameter("foriginSetByValueClass") != null) {
			json = request.getParameter("foriginSetByValueClass");
			option = "foriginSetByValueClass";
		}		
		else if (request.getParameter("cviewDMValue") != null) {
			json = request.getParameter("cviewDMValue");
			option = "cviewDMValue";
		}
		else if (request.getParameter("cviewDMValueClass") != null) {
			json = request.getParameter("cviewDMValueClass");
			option = "cviewDMValueClass";
		}
		else if (request.getParameter("classTree") != null) {
			json = request.getParameter("classTree");
			option = "classTree";
		}
		if (option.equals("tmpcollection")) {
			String str = URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			String lang = (String) regtJSON.get("lang");
			String name = (String) regtJSON.get("name");
			JSONArray cjson = (JSONArray) regtJSON.get("collection");
			HashSet<URIResource>  members = new HashSet<URIResource>();
			for(int i=0;i<cjson.size();i++){
				JSONObject jsob = (JSONObject)cjson.get(i);
				String genre =(String)jsob.get("etype");
				String eid =(String)jsob.get("eid");
				int entityID = Integer.valueOf(eid);
				if(genre.equals(Entity.URI_ENTITY_Str)){
					try {
						String uriStr  = URIIDCache.getInstance().getURI(entityID);
					    URIResource resource = ResourceFactory.getInstance().createURIResource(uriStr);
					    members.add(resource);
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}else if(genre.equals(Entity.CUSTOM_ENTITY_Str)){
					 HashSet<Integer> set = Entity.getMembersByEntityId(entityID);
					 for(Integer memberID:set){
							try {
								String uriStr  = URIIDCache.getInstance().getURI(memberID);
							    URIResource resource = ResourceFactory.getInstance().createURIResource(uriStr);
							    members.add(resource);
							} catch (Throwable e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
					 }
				}else{
					throw new IllegalArgumentException("实体的类型只能为o或者e");
				}
			}
			if(name==null){
				if(lang.equals("en"))
					name = "untitled";
				else if(lang.equals("zh"))
					name = "未命名";
			}
			CustomCollection entity = new CustomCollection( name, lang,members);
		    entity.serializeTmpCollection();
			int collectionID = entity.getID();
		    ArrayList<Integer> types=  new ArrayList<Integer>();
		    types.addAll(entity.computeCollectionClassTypes(members));
		    Entity.storeClassTypesById(collectionID, types);
			response.getWriter().print(collectionID);
		}else if (option.equals("initViewDMList")) {
			String str =  URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			int collectionID = ((Long) regtJSON.get("collectionID")).intValue();
			String lang = (String) regtJSON.get("lang");
			int classID =  Integer.valueOf((String) regtJSON.get("classID"));
			boolean isInner = Integer.valueOf((String) regtJSON.get("isInner"))==1?true:false;
			//get available query items
			HashSet<DataMemberItem> alldatamembers = CustomCollection.getAvailableDMsOfCollection(lang, collectionID, isInner, classID);
			int topk = 5;
			ArrayList<DataMemberItem> topdatamembers = CustomCollection.getTopDataMembers(alldatamembers,topk); 

			JSONArray resultArray = new JSONArray();
			ArrayList<DataMember> datamembers = null;

			ArrayList<Integer> inverses = new ArrayList<Integer>();
			ArrayList<Integer> ids = new ArrayList<Integer>();
			for (int i = 0; i < topdatamembers.size(); i++) {
				int dmtype = 0;
				int dmid = 0;
				String name = null;
				int inverse = 0;
				DataMemberItem item = topdatamembers.get(i);
				dmtype =item.getDMType();
				dmid = item.getDMID();
				name = item.getName();
				inverse = item.getInverse()?1:0;
				int vtype = item.getValueType();

				JSONObject jsob = new JSONObject();
				jsob.put("dmtype", dmtype);
				jsob.put("dmid", dmid);
				jsob.put("name", name);
				jsob.put("inverse", inverse);
				resultArray.add(jsob);
			}

			JSONObject resob = new JSONObject();
			resob.put("list", resultArray);
			response.getWriter().print(resob);
		}else if (option.equals("initViewDMTable")) {
			String str =  URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			int collectionID = ((Long) regtJSON.get("collectionID")).intValue();
			String lang = (String) regtJSON.get("lang");
			int classID =  Integer.valueOf((String) regtJSON.get("classID"));
			boolean isInner = Integer.valueOf((String) regtJSON.get("isInner"))==1?true:false;
			//get available query items
			HashSet<DataMemberItem> alldatamembers = CustomCollection.getAvailableDMsOfCollection(lang, collectionID, isInner, classID);
			int topk = 5;
			ArrayList<DataMemberItem> topdatamembers = CustomCollection.getTopDataMembers(alldatamembers,topk); 

			JSONArray resultArray = new JSONArray();
			ArrayList<DataMember> datamembers = null;

			ArrayList<Integer> inverses = new ArrayList<Integer>();
			ArrayList<Integer> ids = new ArrayList<Integer>();
			for (int i = 0; i < topdatamembers.size(); i++) {
				int dmtype = 0;
				int dmid = 0;
				String name = null;
				int inverse = 0;
				DataMemberItem item = topdatamembers.get(i);
				dmtype =item.getDMType();
				dmid = item.getDMID();
				name = item.getName();
				inverse = item.getInverse()?1:0;

				JSONObject jsob = new JSONObject();
				jsob.put("dmtype", dmtype);
				jsob.put("dmid", dmid);
				jsob.put("name", name);
				jsob.put("inverse", inverse);
				resultArray.add(jsob);
			}
//			HashSet<Integer> members = Entity.getMembersByEntityId(collectionID);
//			JSONArray memArray = new JSONArray();
//			for(int memberID : members){
//				JSONObject jsob = new JSONObject();
//				jsob.put("eid", memberID);
//				try {
//					String uriStr  = URIIDCache.getInstance().getURI(memberID);
//				    jsob.put("euri", uriStr);
//				    String name = URILabelCache.getInstance().getLabel(memberID, lang);
//				    if(name==null || name.trim().length()==0){
//				    	name = URIUtil.getLocalname(uriStr);
//				    }
//				    jsob.put("ename", name);
//				} catch (Throwable e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
////				System.out.println("jsob:"+jsob.toJSONString()+"|"+memberID+"|"+lang);
//				memArray.add(jsob);
//			}
			JSONObject resob = new JSONObject();
			resob.put("list", resultArray);
//			resob.put("elist", memArray);
			response.getWriter().print(resob);
		}else if (option.equals("foriginSet")) {
			String str =  URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			String lang = (String) regtJSON.get("lang");
			int etype =  Integer.valueOf((String) regtJSON.get("etype"));
			int eid =  Integer.valueOf((String) regtJSON.get("eid"));
			int dmtype =  ((Long) regtJSON.get("dmtype")).intValue();
			int dmid =  ((Long) regtJSON.get("dmid")).intValue();
			boolean inverse = ((Long) regtJSON.get("inverse"))==1?true:false;

			JSONArray result = new JSONArray();
			HashSet<mEntity> filteredMembers = CollectionReasoner.filterOriginMembers(dmtype, dmid, inverse, etype, eid) ;
			for(mEntity entity:filteredMembers){
				String memTypeStr = Entity.transTypeID2Str(entity.getEtype());
				int memeid = entity.getEid();
				JSONObject jsob = new JSONObject();
				jsob.put("etype", memTypeStr);
				jsob.put("eid", memeid);
				result.add(jsob);
			}
			response.getWriter().print(result);
		}
		else if (option.equals("foriginSetByEqualValue")) {
			String str =  URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			String lang = (String) regtJSON.get("lang");
			int etype =  Integer.valueOf((String) regtJSON.get("etype"));
			int eid =  Integer.valueOf((String) regtJSON.get("eid"));
			int dmtype =  ((Long) regtJSON.get("dmtype")).intValue();
			int dmid =  ((Long) regtJSON.get("dmid")).intValue();
			boolean inverse = ((Long) regtJSON.get("inverse"))==1?true:false;
			JSONArray varray = (JSONArray)regtJSON.get("varray");
			
			HashSet<Resource> resources = new HashSet<Resource>();
			for(int i=0;i<varray.size();i++){
				JSONObject jsob = (JSONObject)varray.get(i);
				String vetype = (String)jsob.get("etype");
				if(vetype.equals("l")){
					String label = (String)jsob.get("label");
					String literalLang= (String)jsob.get("literalLang");
					int  literalTypeID= Integer.valueOf((String)jsob.get("literalType"));
					Resource r ;
					if(literalTypeID>0){
						String typeURI = null;
						try {
							typeURI = URIIDCache.getInstance().getURI(literalTypeID);
						} catch (Throwable e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						r = ResourceFactory.getInstance().createTypedLiteral(label, typeURI) ;
					}else{
						r = ResourceFactory.getInstance().createPlainLiteral(label, literalLang);
					}
					 
					resources.add(r);
				}else{
					if(!vetype.equals(Entity.URI_ENTITY_Str)){
						throw new IllegalArgumentException("Member must be uri entity");
					}
					int veid = Integer.parseInt((String)jsob.get("eid"));
					try {
						String uri = URIIDCache.getInstance().getURI(veid);
						Resource r = ResourceFactory.getInstance().createURIResource(uri);
						resources.add(r);
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			}

			JSONArray result = new JSONArray();
			HashSet<mEntity> filteredMembers = CollectionReasoner.filterOriginMembersByEqual(dmtype, dmid, inverse, etype, eid,resources) ;
			for(mEntity entity:filteredMembers){
				String memTypeStr = Entity.transTypeID2Str(entity.getEtype());
				int memeid = entity.getEid();
				JSONObject jsob = new JSONObject();
				jsob.put("etype", memTypeStr);
				jsob.put("eid", memeid);
				result.add(jsob);
			}
			response.getWriter().print(result);
		}
		else if (option.equals("foriginSetByMemberClass")) {
			String str =  URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			String lang = (String) regtJSON.get("lang");
			int etype =  Integer.valueOf((String) regtJSON.get("etype"));
			int eid =  Integer.valueOf((String) regtJSON.get("eid"));
			int dmtype =  ((Long) regtJSON.get("dmtype")).intValue();
			int dmid =  ((Long) regtJSON.get("dmid")).intValue();
			boolean inverse = ((Long) regtJSON.get("inverse"))==1?true:false;
			//每个元素表示强连通分支里面的类集合，或关系
			JSONArray carray = (JSONArray)regtJSON.get("carray");
			
			HashSet<Integer> classes = new HashSet<Integer>();
			for(int i=0;i<carray.size();i++){
                String classSetStr = (String)carray.get(i);		
                String[] classStrs = classSetStr.split(",");
                for(String cstr:classStrs){
                	classes.add(Integer.valueOf(cstr));
                }
			}

			JSONArray result = new JSONArray();
			HashSet<mEntity> filteredMembers = CollectionReasoner.filterOriginMembersByMemberClass(dmtype, dmid, inverse, etype, eid,classes) ;
			for(mEntity entity:filteredMembers){
				String memTypeStr = Entity.transTypeID2Str(entity.getEtype());
				int memeid = entity.getEid();
				JSONObject jsob = new JSONObject();
				jsob.put("etype", memTypeStr);
				jsob.put("eid", memeid);
				result.add(jsob);
			}
			response.getWriter().print(result);
		}
		else if (option.equals("foriginSetByValueClass")) {
			String str =  URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			int etype =  Integer.valueOf((String) regtJSON.get("etype"));
			int eid =  Integer.valueOf((String) regtJSON.get("eid"));
			int dmtype =  ((Long) regtJSON.get("dmtype")).intValue();
			int dmid =  ((Long) regtJSON.get("dmid")).intValue();
			boolean inverse = ((Long) regtJSON.get("inverse"))==1?true:false;
			//每个元素表示强连通分支里面的类集合，或关系
			JSONArray carray = (JSONArray)regtJSON.get("carray");
			
			HashSet<Integer> classes = new HashSet<Integer>();
			for(int i=0;i<carray.size();i++){
                String classSetStr = (String)carray.get(i);		
                String[] classStrs = classSetStr.split(",");
                for(String cstr:classStrs){
                	classes.add(Integer.valueOf(cstr));
                }
			}

			JSONArray result = new JSONArray();
			HashSet<mEntity> filteredMembers = CollectionReasoner.filterOriginMembersByValueClass(dmtype, dmid, inverse, etype, eid,classes) ;
			for(mEntity entity:filteredMembers){
				String memTypeStr = Entity.transTypeID2Str(entity.getEtype());
				int memeid = entity.getEid();
				JSONObject jsob = new JSONObject();
				jsob.put("etype", memTypeStr);
				jsob.put("eid", memeid);
				result.add(jsob);
			}
			response.getWriter().print(result);
		}
		else if(option.equals("cviewDMValueClass")){
			String str = URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			int dmtype =((Long)regtJSON.get("dmtype")).intValue() ;
			int dmid = ((Long)regtJSON.get("dmid")).intValue() ;
			int inverse =  ((Long)regtJSON.get("inverse")).intValue() ;
 			String lang = (String)regtJSON.get("lang") ;
 			JSONArray memberjson = (JSONArray)regtJSON.get("members");
 			HashSet<Integer> classes = CollectionReasoner.computeCollectionDMValueClass(dmtype,dmid,
 					inverse,lang, memberjson) 	;
 			ReducedClassTree ctree = new ReducedClassTree(classes);
 			JSONArray  tree = ctree.getClassesJSONArray(lang);
 			JSONObject result = new JSONObject();
			String t = URLEncoder.encode(tree.toString(),"utf-8").replace("+", "%20");
			result.put("tree", t);
			response.getWriter().print(result);
		}
		else if (option.equals("cviewDMValue")) {
			String str = URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
			int dmtype =((Long)regtJSON.get("dmtype")).intValue() ;
			int dmid = ((Long)regtJSON.get("dmid")).intValue() ;
			int inverse =  ((Long)regtJSON.get("inverse")).intValue() ;
 			String lang = (String)regtJSON.get("lang") ;
 			JSONArray memberjson = (JSONArray)regtJSON.get("members");
 			
 			//取值JSON数组
 			JSONArray valueArray = new JSONArray();
 			//推理用到的相关数据源
 			JSONArray docArray = new JSONArray();
 			ArrayList<Boolean> flags = CollectionReasoner.computeCollectionDMValue(dmtype,dmid,
 					inverse,lang, memberjson,valueArray,docArray ) 	;
 			boolean waitData = flags.get(0);
 			
 			JSONObject result = new JSONObject();
 			
 			/**
 			 * 通过两层来控制是否结束
 			 * 第一层是推理是否完结
 			 * 第二层是URI是否取到需要的Label
 			 * 因此理论上走了三步来下载文档
 			 */
 			String status = ViewServlet.STATUS_STOP;
 			if(valueArray.size()>= ViewServlet.ALTIMATE_REASONING_RESULT){
 				 status =  ViewServlet.STATUS_STOP;
 			}
 			else if(waitData){
 				status = ViewServlet.STATUS_WAIT_DATA;
 			}
 			
 			result.put("status", status) ;
 			result.put("srcDocs",docArray);
 			result.put("values", valueArray) ;
 			response.getWriter().print(result) ;
		}
		else if (option.equals("classTree")) {
			String str = URLDecoder.decode(json,"utf-8");
			JSONObject regtJSON = (JSONObject) JSONValue.parse(str);
 			String lang = (String)regtJSON.get("lang") ;
 			
 			JSONArray memberjson = (JSONArray)regtJSON.get("members");
 			HashSet<Integer> uris = new HashSet<Integer>();
 			for(int i=0;i<memberjson.size();i++){
 				JSONObject memob = (JSONObject)memberjson.get(i);
 				int etype = Entity.transTypeStr2ID((String)memob.get("etype"));
 				int eid = Integer.valueOf((String)memob.get("eid"));
 				if(etype!=Entity.URI_ENTITY){
 					throw new IllegalArgumentException("Member must be uri entity");
 				}
 				uris.add(eid);
 			}
 			
 			HashSet<Integer> classes = new 	HashSet<Integer>();
 			for(Integer id:uris){
 				try {
 					classes.addAll(URITypeCache.getInstance().getTypes(id));
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
 			}
 			ReducedClassTree ctree = new ReducedClassTree(classes);
 			JSONArray  tree = ctree.getClassesJSONArray(lang);
 			JSONObject result = new JSONObject();
			String t = URLEncoder.encode(tree.toString(),"utf-8").replace("+", "%20");
			result.put("tree", t);
			response.getWriter().print(result);
		}
	}
}
